﻿// Decompiled with JetBrains decompiler
// Type: UnityEngine.Events.UnityEventBase
// Assembly: UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E6AE6B5A-2752-4B07-9528-C8B77C62CE79
// Assembly location: C:\Users\windys\Unity\2021.3.39f1c1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll
// XML documentation location: C:\Users\windys\Unity\2021.3.39f1c1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.xml

using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine.Scripting;
using UnityEngine.Serialization;

#nullable disable
namespace UnityEngine.Events
{
  /// <summary>
  ///   <para>Abstract base class for UnityEvents.</para>
  /// </summary>
  [UsedByNativeCode]
  [Serializable]
  public abstract class UnityEventBase : ISerializationCallbackReceiver
  {
    private InvokableCallList m_Calls;
    [FormerlySerializedAs("m_PersistentListeners")]
    [SerializeField]
    private PersistentCallGroup m_PersistentCalls;
    private bool m_CallsDirty = true;

    protected UnityEventBase()
    {
      this.m_Calls = new InvokableCallList();
      this.m_PersistentCalls = new PersistentCallGroup();
    }

    void ISerializationCallbackReceiver.OnBeforeSerialize() => this.DirtyPersistentCalls();

    void ISerializationCallbackReceiver.OnAfterDeserialize() => this.DirtyPersistentCalls();

    protected MethodInfo FindMethod_Impl(string name, object targetObj)
    {
      return this.FindMethod_Impl(name, targetObj.GetType());
    }

    protected abstract MethodInfo FindMethod_Impl(string name, System.Type targetObjType);

    internal abstract BaseInvokableCall GetDelegate(object target, MethodInfo theFunction);

    internal MethodInfo FindMethod(PersistentCall call)
    {
      System.Type argumentType = typeof (UnityEngine.Object);
      if (!string.IsNullOrEmpty(call.arguments.unityObjectArgumentAssemblyTypeName))
        argumentType = System.Type.GetType(call.arguments.unityObjectArgumentAssemblyTypeName, false) ?? typeof (UnityEngine.Object);
      System.Type listenerType = call.target != (UnityEngine.Object) null ? call.target.GetType() : System.Type.GetType(call.targetAssemblyTypeName, false);
      return this.FindMethod(call.methodName, listenerType, call.mode, argumentType);
    }

    internal MethodInfo FindMethod(
      string name,
      System.Type listenerType,
      PersistentListenerMode mode,
      System.Type argumentType)
    {
      switch (mode)
      {
        case PersistentListenerMode.EventDefined:
          return this.FindMethod_Impl(name, listenerType);
        case PersistentListenerMode.Void:
          return UnityEventBase.GetValidMethodInfo(listenerType, name, new System.Type[0]);
        case PersistentListenerMode.Object:
          return UnityEventBase.GetValidMethodInfo(listenerType, name, new System.Type[1]
          {
            argumentType ?? typeof (UnityEngine.Object)
          });
        case PersistentListenerMode.Int:
          return UnityEventBase.GetValidMethodInfo(listenerType, name, new System.Type[1]
          {
            typeof (int)
          });
        case PersistentListenerMode.Float:
          return UnityEventBase.GetValidMethodInfo(listenerType, name, new System.Type[1]
          {
            typeof (float)
          });
        case PersistentListenerMode.String:
          return UnityEventBase.GetValidMethodInfo(listenerType, name, new System.Type[1]
          {
            typeof (string)
          });
        case PersistentListenerMode.Bool:
          return UnityEventBase.GetValidMethodInfo(listenerType, name, new System.Type[1]
          {
            typeof (bool)
          });
        default:
          return (MethodInfo) null;
      }
    }

    /// <summary>
    ///   <para>Get the number of registered persistent listeners.</para>
    /// </summary>
    public int GetPersistentEventCount() => this.m_PersistentCalls.Count;

    /// <summary>
    ///   <para>Get the target component of the listener at index index.</para>
    /// </summary>
    /// <param name="index">Index of the listener to query.</param>
    public UnityEngine.Object GetPersistentTarget(int index)
    {
      return this.m_PersistentCalls.GetListener(index)?.target;
    }

    /// <summary>
    ///   <para>Get the target method name of the listener at index index.</para>
    /// </summary>
    /// <param name="index">Index of the listener to query.</param>
    public string GetPersistentMethodName(int index)
    {
      PersistentCall listener = this.m_PersistentCalls.GetListener(index);
      return listener != null ? listener.methodName : string.Empty;
    }

    private void DirtyPersistentCalls()
    {
      this.m_Calls.ClearPersistent();
      this.m_CallsDirty = true;
    }

    private void RebuildPersistentCallsIfNeeded()
    {
      if (!this.m_CallsDirty)
        return;
      this.m_PersistentCalls.Initialize(this.m_Calls, this);
      this.m_CallsDirty = false;
    }

    /// <summary>
    ///   <para>Modify the execution state of a persistent listener.</para>
    /// </summary>
    /// <param name="index">Index of the listener to query.</param>
    /// <param name="state">State to set.</param>
    public void SetPersistentListenerState(int index, UnityEventCallState state)
    {
      PersistentCall listener = this.m_PersistentCalls.GetListener(index);
      if (listener != null)
        listener.callState = state;
      this.DirtyPersistentCalls();
    }

    /// <summary>
    ///   <para>Returns the execution state of a persistent listener.</para>
    /// </summary>
    /// <param name="index">Index of the listener to query.</param>
    /// <returns>
    ///   <para>Execution state of the persistent listener.</para>
    /// </returns>
    public UnityEventCallState GetPersistentListenerState(int index)
    {
      if (index < 0 || index > this.m_PersistentCalls.Count)
        throw new IndexOutOfRangeException(string.Format("Index {0} is out of range of the {1} persistent listeners.", (object) index, (object) this.GetPersistentEventCount()));
      return this.m_PersistentCalls.GetListener(index).callState;
    }

    protected void AddListener(object targetObj, MethodInfo method)
    {
      this.m_Calls.AddListener(this.GetDelegate(targetObj, method));
    }

    internal void AddCall(BaseInvokableCall call) => this.m_Calls.AddListener(call);

    protected void RemoveListener(object targetObj, MethodInfo method)
    {
      this.m_Calls.RemoveListener(targetObj, method);
    }

    /// <summary>
    ///   <para>Remove all non-persistent (ie created from script) listeners  from the event.</para>
    /// </summary>
    public void RemoveAllListeners() => this.m_Calls.Clear();

    internal List<BaseInvokableCall> PrepareInvoke()
    {
      this.RebuildPersistentCallsIfNeeded();
      return this.m_Calls.PrepareInvoke();
    }

    protected void Invoke(object[] parameters)
    {
      List<BaseInvokableCall> baseInvokableCallList = this.PrepareInvoke();
      for (int index = 0; index < baseInvokableCallList.Count; ++index)
        baseInvokableCallList[index].Invoke(parameters);
    }

    public override string ToString() => base.ToString() + " " + this.GetType().FullName;

    /// <summary>
    ///   <para>Given an object, function name, and a list of argument types; find the method that matches.</para>
    /// </summary>
    /// <param name="obj">Object to search for the method.</param>
    /// <param name="functionName">Function name to search for.</param>
    /// <param name="argumentTypes">Argument types for the function.</param>
    public static MethodInfo GetValidMethodInfo(
      object obj,
      string functionName,
      System.Type[] argumentTypes)
    {
      return UnityEventBase.GetValidMethodInfo(obj.GetType(), functionName, argumentTypes);
    }

    /// <summary>
    ///   <para>Given an object type, function name, and a list of argument types; find the method that matches.</para>
    /// </summary>
    /// <param name="objectType">Object type to search for the method.</param>
    /// <param name="functionName">Function name to search for.</param>
    /// <param name="argumentTypes">Argument types for the function.</param>
    public static MethodInfo GetValidMethodInfo(
      System.Type objectType,
      string functionName,
      System.Type[] argumentTypes)
    {
      for (; objectType != typeof (object) && objectType != null; objectType = objectType.BaseType)
      {
        MethodInfo method = objectType.GetMethod(functionName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, (Binder) null, argumentTypes, (ParameterModifier[]) null);
        if (method != null)
        {
          ParameterInfo[] parameters = method.GetParameters();
          bool flag = true;
          int index = 0;
          foreach (ParameterInfo parameterInfo in parameters)
          {
            flag = argumentTypes[index].IsPrimitive == parameterInfo.ParameterType.IsPrimitive;
            if (flag)
              ++index;
            else
              break;
          }
          if (flag)
            return method;
        }
      }
      return (MethodInfo) null;
    }

    protected bool ValidateRegistration(
      MethodInfo method,
      object targetObj,
      PersistentListenerMode mode)
    {
      return this.ValidateRegistration(method, targetObj, mode, typeof (UnityEngine.Object));
    }

    protected bool ValidateRegistration(
      MethodInfo method,
      object targetObj,
      PersistentListenerMode mode,
      System.Type argumentType)
    {
      if (method == null)
        throw new ArgumentNullException(nameof (method), UnityString.Format("Can not register null method on {0} for callback!", targetObj));
      if (method.DeclaringType == null)
        throw new NullReferenceException(UnityString.Format("Method '{0}' declaring type is null, global methods are not supported", (object) method.Name));
      System.Type type;
      if (!method.IsStatic)
      {
        UnityEngine.Object @object = targetObj as UnityEngine.Object;
        type = !(@object == (UnityEngine.Object) null) && @object.GetInstanceID() != 0 ? @object.GetType() : throw new ArgumentException(UnityString.Format("Could not register callback {0} on {1}. The class {2} does not derive from UnityEngine.Object", (object) method.Name, targetObj, targetObj == null ? (object) "null" : (object) targetObj.GetType().ToString()));
        if (!method.DeclaringType.IsAssignableFrom(type))
          throw new ArgumentException(UnityString.Format("Method '{0}' declaring type '{1}' is not assignable from object type '{2}'", (object) method.Name, (object) method.DeclaringType.Name, (object) @object.GetType().Name));
      }
      else
        type = method.DeclaringType;
      if (this.FindMethod(method.Name, type, mode, argumentType) != null)
        return true;
      Debug.LogWarning((object) UnityString.Format("Could not register listener {0}.{1} on {2} the method could not be found.", targetObj, (object) method, (object) this.GetType()));
      return false;
    }

    internal void AddPersistentListener() => this.m_PersistentCalls.AddListener();

    protected void RegisterPersistentListener(int index, object targetObj, MethodInfo method)
    {
      this.RegisterPersistentListener(index, targetObj, targetObj.GetType(), method);
    }

    protected void RegisterPersistentListener(
      int index,
      object targetObj,
      System.Type targetObjType,
      MethodInfo method)
    {
      if (!this.ValidateRegistration(method, targetObj, PersistentListenerMode.EventDefined))
        return;
      this.m_PersistentCalls.RegisterEventPersistentListener(index, targetObj as UnityEngine.Object, targetObjType, method.Name);
      this.DirtyPersistentCalls();
    }

    internal void RemovePersistentListener(UnityEngine.Object target, MethodInfo method)
    {
      if (method == null)
        return;
      this.m_PersistentCalls.RemoveListeners(target, method.Name);
      this.DirtyPersistentCalls();
    }

    internal void RemovePersistentListener(int index)
    {
      this.m_PersistentCalls.RemoveListener(index);
      this.DirtyPersistentCalls();
    }

    internal void UnregisterPersistentListener(int index)
    {
      this.m_PersistentCalls.UnregisterPersistentListener(index);
      this.DirtyPersistentCalls();
    }

    internal void AddVoidPersistentListener(UnityAction call)
    {
      int persistentEventCount = this.GetPersistentEventCount();
      this.AddPersistentListener();
      this.RegisterVoidPersistentListener(persistentEventCount, call);
    }

    internal void RegisterVoidPersistentListener(int index, UnityAction call)
    {
      if (call == null)
      {
        Debug.LogWarning((object) "Registering a Listener requires an action");
      }
      else
      {
        if (!this.ValidateRegistration(call.Method, call.Target, PersistentListenerMode.Void))
          return;
        this.m_PersistentCalls.RegisterVoidPersistentListener(index, call.Target as UnityEngine.Object, call.Method.DeclaringType, call.Method.Name);
        this.DirtyPersistentCalls();
      }
    }

    internal void RegisterVoidPersistentListenerWithoutValidation(
      int index,
      UnityEngine.Object target,
      string methodName)
    {
      this.RegisterVoidPersistentListenerWithoutValidation(index, target, target.GetType(), methodName);
    }

    internal void RegisterVoidPersistentListenerWithoutValidation(
      int index,
      UnityEngine.Object target,
      System.Type targetType,
      string methodName)
    {
      this.m_PersistentCalls.RegisterVoidPersistentListener(index, target, targetType, methodName);
      this.DirtyPersistentCalls();
    }

    internal void AddIntPersistentListener(UnityAction<int> call, int argument)
    {
      int persistentEventCount = this.GetPersistentEventCount();
      this.AddPersistentListener();
      this.RegisterIntPersistentListener(persistentEventCount, call, argument);
    }

    internal void RegisterIntPersistentListener(int index, UnityAction<int> call, int argument)
    {
      if (call == null)
      {
        Debug.LogWarning((object) "Registering a Listener requires an action");
      }
      else
      {
        if (!this.ValidateRegistration(call.Method, call.Target, PersistentListenerMode.Int))
          return;
        this.m_PersistentCalls.RegisterIntPersistentListener(index, call.Target as UnityEngine.Object, call.Method.DeclaringType, argument, call.Method.Name);
        this.DirtyPersistentCalls();
      }
    }

    internal void AddFloatPersistentListener(UnityAction<float> call, float argument)
    {
      int persistentEventCount = this.GetPersistentEventCount();
      this.AddPersistentListener();
      this.RegisterFloatPersistentListener(persistentEventCount, call, argument);
    }

    internal void RegisterFloatPersistentListener(
      int index,
      UnityAction<float> call,
      float argument)
    {
      if (call == null)
      {
        Debug.LogWarning((object) "Registering a Listener requires an action");
      }
      else
      {
        if (!this.ValidateRegistration(call.Method, call.Target, PersistentListenerMode.Float))
          return;
        this.m_PersistentCalls.RegisterFloatPersistentListener(index, call.Target as UnityEngine.Object, call.Method.DeclaringType, argument, call.Method.Name);
        this.DirtyPersistentCalls();
      }
    }

    internal void AddBoolPersistentListener(UnityAction<bool> call, bool argument)
    {
      int persistentEventCount = this.GetPersistentEventCount();
      this.AddPersistentListener();
      this.RegisterBoolPersistentListener(persistentEventCount, call, argument);
    }

    internal void RegisterBoolPersistentListener(int index, UnityAction<bool> call, bool argument)
    {
      if (call == null)
      {
        Debug.LogWarning((object) "Registering a Listener requires an action");
      }
      else
      {
        if (!this.ValidateRegistration(call.Method, call.Target, PersistentListenerMode.Bool))
          return;
        this.m_PersistentCalls.RegisterBoolPersistentListener(index, call.Target as UnityEngine.Object, call.Method.DeclaringType, argument, call.Method.Name);
        this.DirtyPersistentCalls();
      }
    }

    internal void AddStringPersistentListener(UnityAction<string> call, string argument)
    {
      int persistentEventCount = this.GetPersistentEventCount();
      this.AddPersistentListener();
      this.RegisterStringPersistentListener(persistentEventCount, call, argument);
    }

    internal void RegisterStringPersistentListener(
      int index,
      UnityAction<string> call,
      string argument)
    {
      if (call == null)
      {
        Debug.LogWarning((object) "Registering a Listener requires an action");
      }
      else
      {
        if (!this.ValidateRegistration(call.Method, call.Target, PersistentListenerMode.String))
          return;
        this.m_PersistentCalls.RegisterStringPersistentListener(index, call.Target as UnityEngine.Object, call.Method.DeclaringType, argument, call.Method.Name);
        this.DirtyPersistentCalls();
      }
    }

    internal void AddObjectPersistentListener<T>(UnityAction<T> call, T argument) where T : UnityEngine.Object
    {
      int persistentEventCount = this.GetPersistentEventCount();
      this.AddPersistentListener();
      this.RegisterObjectPersistentListener<T>(persistentEventCount, call, argument);
    }

    internal void RegisterObjectPersistentListener<T>(int index, UnityAction<T> call, T argument) where T : UnityEngine.Object
    {
      if (call == null)
        throw new ArgumentNullException(nameof (call), "Registering a Listener requires a non null call");
      if (!this.ValidateRegistration(call.Method, call.Target, PersistentListenerMode.Object, (UnityEngine.Object) argument == (UnityEngine.Object) null ? typeof (UnityEngine.Object) : argument.GetType()))
        return;
      this.m_PersistentCalls.RegisterObjectPersistentListener(index, call.Target as UnityEngine.Object, call.Method.DeclaringType, (UnityEngine.Object) argument, call.Method.Name);
      this.DirtyPersistentCalls();
    }
  }
}
